package com.yuan;


import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

/**
 * Class that manages intensity values by segments on a number line.
 * Segments are intervals from -infinity to infinity.
 */
public class IntensitySegments {
    /**
     * Represents a segment with a position and intensity value.
     */
    private static class Segment {
        public final int position;
        public int intensity;

        public Segment(int position, int intensity) {
            this.position = position;
            this.intensity = intensity;
        }
    }

    private final List<Segment> segments;

    /**
     * Initializes an empty IntensitySegments instance.
     */
    public IntensitySegments() {
        this.segments = new ArrayList<>();
    }

    /**
     * Adds the given amount to the intensity values in the range [from, to).
     *
     * @param from   The start of the range (inclusive)
     * @param to     The end of the range (exclusive)
     * @param amount The amount to add to the intensity
     */
    public void add(int from, int to, int amount) {
        if (from >= to || amount == 0) {
            return; // No-op for invalid range or zero amount
        }

        // Get current intensity at 'from' position
        int fromIntensity = getIntensityAt(from);

        // Get current intensity at 'to' position
        int toIntensity = getIntensityAt(to);

        // Insert or update the segment at 'from' position
        updateSegment(from, fromIntensity + amount);

        // Insert or update the segment at 'to' position
        updateSegment(to, toIntensity);

        // Process overlapping segments within the range
        processOverlappingSegments(from, to, amount);

        // Clean up segments with the same intensity as their neighbors
        cleanupSegments();
    }

    /**
     * Sets the intensity to the given amount in the range [from, to).
     *
     * @param from   The start of the range (inclusive)
     * @param to     The end of the range (exclusive)
     * @param amount The intensity value to set
     */
    public void set(int from, int to, int amount) {
        if (from >= to) {
            return; // No-op for invalid range
        }

        // Get current intensity at 'to' position
        int toIntensity = getIntensityAt(to);

        // Remove all segments within the range
        segments.removeIf(segment -> segment.position > from && segment.position < to);

        // Insert segments at 'from' and 'to'
        updateSegment(from, amount);
        updateSegment(to, toIntensity);

        // Clean up unnecessary segments
        cleanupSegments();
    }

    /**
     * Returns a string representation of the segments.
     *
     * @return A string representation of the segments
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");

        for (int i = 0; i < segments.size(); i++) {
            Segment segment = segments.get(i);
            sb.append("[").append(segment.position).append(",").append(segment.intensity).append("]");
            if (i < segments.size() - 1) {
                sb.append(",");
            }
        }

        sb.append("]");
        return sb.toString();
    }

    /**
     * Gets the intensity value at the given position.
     *
     * @param position The position to query
     * @return The intensity value at the position
     */
    private int getIntensityAt(int position) {
        // Find the last segment with position <= the query position
        int intensity = 0;
        for (Segment segment : segments) {
            if (segment.position <= position) {
                intensity = segment.intensity;
            } else {
                break;
            }
        }
        return intensity;
    }

    /**
     * Updates or inserts a segment at the given position with the given intensity.
     *
     * @param position  The position of the segment
     * @param intensity The intensity value
     */
    private void updateSegment(int position, int intensity) {
        // Find if this position already exists
        for (int i = 0; i < segments.size(); i++) {
            Segment segment = segments.get(i);
            if (segment.position == position) {
                segment.intensity = intensity;
                return;
            } else if (segment.position > position) {
                // Insert at this position
                segments.add(i, new Segment(position, intensity));
                return;
            }
        }

        // If we get here, we need to append to the end
        segments.add(new Segment(position, intensity));
    }

    /**
     * Processes all segments that overlap with the range [from, to) and adds amount to their intensity.
     *
     * @param from   The start of the range (inclusive)
     * @param to     The end of the range (exclusive)
     * @param amount The amount to add to the intensity
     */
    private void processOverlappingSegments(int from, int to, int amount) {
        for (Segment segment : segments) {
            if (segment.position > from && segment.position < to) {
                segment.intensity += amount;
            }
        }
    }

    /**
     * Cleans up segments with the same intensity as their previous segment.
     */
    private void cleanupSegments() {
        // First, sort segments by position
        segments.sort(Comparator.comparingInt(s -> s.position));

        // Remove segments where the intensity is the same as the previous segment
        Iterator<Segment> iterator = segments.iterator();
        Segment prev = null;

        while (iterator.hasNext()) {
            Segment current = iterator.next();
            if (prev != null && prev.intensity == current.intensity) {
                iterator.remove();
            } else {
                prev = current;
            }
        }

        // Remove segments with intensity 0 at the beginning
        if (!segments.isEmpty() && segments.get(0).intensity == 0) {
            segments.remove(0);
        }
    }}